Framework / Data / Data Tables
In This Topic
    Data Tables
    In This Topic
     About Data Tables

    In NOV relational data tables are represented by the abstract NDataTable class. It represents a matrix that has arbitrary number of fields (columns) and rows. The cells that correspond to each specific field holds values of a field specific data type.

    The methods and properties of the NDataTable class help you work with all types of data tables in a consistent and intuitive manner. NDataTable exposes various operations that help you add/remove fields and rows, get or set cell values as well as perform different queries. These operations are discussed in details in the following sections of this topic.

     Types of Data Tables

    NOV implements the following types of data tables:

    • NMemoryDataTable - represents an in-memory data table. This data table implementation uses a column based storage to store the data, which greatly increases the compactness of the in-memory stored data. The NMemoryDataTable supports all data table operations.
    Create a NMemoryDataTable
    Copy Code
    // create a data table with two fields
    NMemoryDataTable dataTable = new NMemoryDataTable(
        new NFieldInfo("Name", typeof(string)),
        new NFieldInfo("Birthday", typeof(DateTime)));
    // fill the data table
    dataTable.AddRow("George", new DateTime(1976, 12, 19));
    dataTable.AddRow("Andrew", new DateTime(1982, 9, 27));
    
    • Reflected Objects Data Tables - in practice it is very useful to represent a collection of objects as a data table. In such data tables each object is represented by a row in the data table. The public properties of the objects are the data table fields. In NOV the set of data tables that use this technique derive from the base NReflectionObjectsDataTable class. Following is a description of the reflection objects based data tables:

      Data Tables for binding to .NET Collection Interfaces

      NIListDataTable Represents the objects contained inside an IList implementation as a data table. You can add/remove/insert rows to this type of data table. You cannot modify the data table columns.
      NIEnumerableDataTable Represents the objects contained inside an IEnumerable implementation as a data table. Internally this data table is making a snapshot of the objects provided by the IEnumerable. This snapshot is performed at the time of creation. You cannot add/remove/insert rows to this type of data table or modify the data table columns.
      The NIListDataTable and NIEnumerableDataTable use the first object in the list to determine the data table fields. 

      Create a NIListDataTable
      Copy Code
      public class Person
      {
          public Person(string name, DateTime birthday)
          {
              Name = name;
              Birthday = birthday;
          }
          public string Name { get; set; }
          public DateTime Birthday { get; set; }
      }
      ...
      ArrayList arrayList = new ArrayList(); // ArrayList implements IList
      arrayList.Add(new Person("George", new DateTime(1976, 12, 19)));
      arrayList.Add(new Person("Andrew", new DateTime(1982, 9, 27)));
      NIListDataTable dataTable = new NIListDataTable(arrayList);
      
      NOV also provides support the .NET generic IList<> and IEnumerable<> interfaces:

      Data Tables for binding to .NET Generic Collection Interfaces

      NGenericIListDataTable Represents the objects contained inside an IList<> implementation as a data table. You can add/remove/insert rows to this type of data table. You cannot modify the data table columns.
      NGenericIEnumerableDataTable Represents the objects contained inside an IEnumerable<> implementation as a data table. Internally this data table is making a snapshot of the objects provided by the IEnumerable<>. This snapshot is performed at the time of creation. You cannot add/remove/insert rows to this type of data table or modify the data table columns.
      Example Title
      Copy Code
      public class Person
      {
          public Person(string name, DateTime birthday)
          {
              Name = name;
              Birthday = birthday;
          }
          public string Name { get; set; }
          public DateTime Birthday { get; set; }
      }
      ...
      Person[] persons = new Person[]{
          new Person("George", new DateTime(1976, 12, 19)),
          new Person("Andrew", new DateTime(1982, 9, 27))
      };
      NGenericIListDataTable<Person> dataTable = new NGenericIListDataTable<Person>(persons);
      

      Analogously to the .NET collection interfaces, NOV provides support for the NOV generic INCollection<> and INIterable<> interfaces:

      Data Tables for binding to NOV Generic Collection Interfaces
      NGenericINCollectionDataTable Represents the objects contained inside an INCollection<> implementation as a data table. You can add/remove/insert rows to this type of data table. You cannot modify the data table columns.
      NGenericINIterableDataTable Represents the objects contained inside an INIterable<> implementation as a data table. Internally this data table is making a snapshot of the objects provided by the INIterable<>. This snapshot is performed at the time of creation. You cannot add/remove/insert rows to this type of data table or modify the data table columns.
    • NNodeCollectionDataTable - this is a DOM specific data table that takes as input a node collection - that is a node that contains other nodes in its children dimension (see Nodes for more information). The fields of this data table can be the DOM properties and/or child slots of the nodes contained inside the node collection.
    • NFilterDataTable - this is a data table that aggregates another data table and exposes only a subset of the aggregated data table rows.
     Creating a NDataTable from Object

    In the previous section we saw how we can create specific data tables when we know the type of object that we want to expose as data table. For example we have created a NGenericIListDataTable<Person> data table to expose the objects contained inside the Person[] array. 

    The NOV Core libraries are designed to be compiled as portable class libraries. This means that not all types of objects, that you expect to be aggregated as data tables are declared in the portable .NET profile. One such example is the System.Data.DataTable which is not declared in the portable .NET profile. Many platform specific applications however make use of System.Data.DataTable to store data and it makes sense to expose System.Data.DataTable as a NDataTable instance. That is why hosts for which this (and other adaptations) are possible perform this.

    To make use of the full set of objects that can be adapted by NOV and the respective Host that you use, you can use the NDataTable.FromObject method to create a NDataTable that exposes a certain type of object as a data table. The following table summarizes the objects and interfaces that are adaptable by this method:

    Object Or Interface WinForms Host WPF Host WebAssembly Host MonoMac Host Xamarin.Mac

    NOV Hosts Implementations

    System.Data.DataTable yes yes no yes yes

    NOV Core Implementation

    INCollection<>

    yes

    INIterable<>

    yes

    INCollection<>

    yes

    IEnumerable<>

    yes

    IList

    yes

    IEnumerable

    yes

     Data Table Field Operations

    The FieldCount property returns the count of fields (columns) in the data table. You can get an instance of the NFieldInfo structure (holds information about the field, such as its Name, Type, whether the field is nullable and whether the field is readonly) via the GetFieldInfo method. The following code snipped get information about the fields of a data table:

    Getting Field Information
    Copy Code
    for (int i = 0; i < dataTable.FieldCount; i++)
    {
        NFieldInfo fieldInfo = dataTable.GetFieldInfo(i);
        Console.WriteLine("Name:" + fieldInfo.Name);
        Console.WriteLine("Type:" + fieldInfo.Type);
        Console.WriteLine("Nullable:" + fieldInfo.Nullable);
        Console.WriteLine("ReadOnly:" + fieldInfo.ReadOnly);
    }
    

    To obtain the field index for a given field name you can use the GetFieldIndex method.

    For most types of data tables, the set of fields is static - i.e. you cannot add or remove fields or rename them. Certain data tables however (like the NMemoryDataTable) allow that. The following table summarizes the field modification methods and properties:

    Property Method Description

    bool CanAddField

    void AddField(NFieldInfo fieldInfo)

    Adds a field to the data table, if the CanAddField property returns true, otherwise throws an exception.

    bool CanInsertField

    void InsertField(int index, NFieldInfo fieldInfo)

    Inserts a field in the data table, if the CanInsertField property returns true, otherwise throw an exception.

    bool CanRemoveField

    void RemoveField(int index)

    Removes a field from the data table, if the CanRemoveField property returns true, otherwise throw an exception.

    bool CanRenameField

    void RenameField(int fieldIndex, string newFieldName)

    Renames a field from the data table, if the CanRenameField property returns true, otherwise throw an exception.

     

     Data Table Row Operations
    The RowCount property returns the count of rows in the data table. For most types of data tables, the set of rows is dynamic  - i.e. you can add, remove or insert rows. It is important to remember that when adding or inserting rows, you need to provide values from the respective field type. For example:
    Adding Rows to a NDataTable
    Copy Code
    // create a data table with two fields
    NMemoryDataTable dataTable = new NMemoryDataTable(
        new NFieldInfo("Name", typeof(string)),
        new NFieldInfo("Birthday", typeof(DateTime)));
    
    // fill the data table
    dataTable.AddRow("George", new DateTime(1976, 12, 19));
    dataTable.AddRow("Andrew", new DateTime(1982, 9, 27));
    

    Note that when adding rows the AddRow arguments match the fields type and order. Analogously to the field operations, there is a respective property that can help you check whether a specific row modification operation is possible, as summarized by the following table:

    Property Method Description

    bool CanAddRow

    void AddRow()

    Adds a new row, with respective field default values. Throws an exception if CanAddRow is false.

    void AddRow(params object[] values)

    Adds a new row, with the specified values. Throws an exception if CanAddRow is false.

    bool CanInsertRow

    void InsertRow(int index)

    Inserts a new row, with respective field default values. Throws an exception if CanInsertRow is false.

    void InsertRow(int index, object[] values)

    Inserts a new row, with the specified values. Throws an exception if CanInsertRow is false.

    bool CanRemoveRow

    void RemoveRow(int index)

    Removes a row at a concrete index. Throws an exception if CanRemoveRow is false.

    void RemoveAllRows()

    Removes all rows from the data table. Throws an exception if CanRemoveRow is false.
     Data Table Cell Operation

    Several methods and indexers help you get and set data table cell values. To get the cell value of a specific cell you can use the following methods:

    Method Description

    object GetValue(int row, int field)

    Gets the cell value of the specified row and field. The field is specified by index.

    object GetValue(int row, string fieldName)

    Gets the cell value of the specified row and field. The field is specified by name.

    To check if the value of a cell is null, use the NCompare.IsNull static method.

     

    Setting cell values is not always allowed, because specific fields can be marked as readonly. The following table summarized the cell modification methods:

    Method Description

    void SetValue(int row, int field, object value)

    Sets the cell value of the specified row and field. The field is specified by index.

    void SetValue(int row, string fieldName, object value)

    Gets the cell value of the specified row and field. The field is specified by name.

    For example:

    Getting and Setting cell values
    Copy Code
    // create a data table with two fields
    NMemoryDataTable dataTable = new NMemoryDataTable(
        new NFieldInfo("Name", typeof(string)),
        new NFieldInfo("Birthday", typeof(DateTime)));
    
    // fill the data table
    dataTable.AddRow("George", new DateTime(1976, 12, 19));
    dataTable.AddRow("Andrew", new DateTime(1982, 9, 27));
    // using SetValue and GetValue value by field index
    dataTable.SetValue(0, 0, "Ivan");
    string name = (string)dataTable.GetValue(0, 0);
    Console.WriteLine("Name:" + name); // outputs Ivan
    // using indexers by field index
    dataTable[0, 0] = "Anton";
    name = (string)dataTable[0, 0];
    Console.WriteLine("Name:" + name); // outputs Anton
    // using SetValue and GetValue value by field name
    dataTable.SetValue(0, "Name", "Jamie");
    name = (string)dataTable.GetValue(0, "Name");
    Console.WriteLine("Name:" + name); // outputs Jamie
    // using indexers by field name
    dataTable[0, "Name"] = "Dave";
    name = (string)dataTable[0, "Name"];
    Console.WriteLine("Name:" + name); // outputs Dave